// -*- c-basic-offset: 2 default-tab-width: 2 indent-tabs-mode: t -*-
// vim: autoindent tabstop=2 noexpandtab shiftwidth=2 softtabstop=2
#ifndef __BC_H
#	define __BC_H
#	include "Complex.h"
#	include <stdio.h>
#	ifdef __BC_C
#		define DECLARE(var, val) var = val
#	else
#		define DECLARE(var, val) extern var
#	endif
#	define PROTECT_MACRO(...) __VA_ARGS__

#define BC_MAGIC			"RC00"
#define BC_EXTENSION	".rbc"

#define CPOOL_VECTAG 0x80
#define CPOOL_INT 0x01
#define CPOOL_INTSXP (CPOOL_INT | CPOOL_VECTAG)
#define CPOOL_DBL 0x02
#define CPOOL_DBLSXP (CPOOL_DBL | CPOOL_VECTAG)
#define CPOOL_STR 0x03
#define CPOOL_STRSXP (CPOOL_STR | CPOOL_VECTAG)
#define CPOOL_LGL 0x04
#define CPOOL_LGLSXP (CPOOL_LGL | CPOOL_VECTAG)
#define CPOOL_CPX 0x05
#define CPOOL_CPXSXP (CPOOL_CPX | CPOOL_VECTAG)
#define CPOOL_VECSXP 0x80
#define CPOOL_NULL 0x6

///////////////////////////////////
#define CF_NOP 0
#define CF_BT  1
#define CF_RET 2

#define IMM 1 /* Immediate */
#define LBL 2 /* Label */
#define IDX 3 /* Code Pool Entry */
#define IOL 4 /*Index of labels*/
#define IFI 5 /* Index of FunInfo (for closure/promises) */
#define BCPMASK (IMM|LBL|IDX|IOL|IFI) /* Set all flags to true*/
#define BCPLEN 3 /* Number of bits needed to encode flags */

// Flags encoding macros
#define P4(p1, p2, p3, p4) ((p4 << (3*BCPLEN)) | (p3 << (2*BCPLEN)) | (p2 << BCPLEN) | p1)
#define P3(p1, p2, p3) P4(p1, p2, p3, 0)
#define P2(p1, p2) P4(p1, p2, 0, 0)
#define P1(p1) P4(p1, 0, 0, 0)
#define P0() 0
//////////////////////////////////

#define BC_NAME(__bcode) BC_names[(((__bcode >= 0) && (__bcode < BC_LAST)) ? __bcode : BC_LAST)]
#ifdef __BC_C
	const int BC_args[] = {
#	define APPLY_BC(__x, __p, __cf) __p,
#	include "bc.def"
	0
	};
	const char* BC_names[] = {
#	define APPLY_BC(__x, ...) #__x,
#	include "bc.def"
		"UNKNOWN"
	};
#else
	extern const int BC_args[];
	extern const char* BC_names[];
#endif

enum BC_values{
#	define APPLY_BC(__x, ...) BC_##__x,
#	include "bc.def"
		BC_LAST // Just a marker for the last valid BC
};

#define BC_NB_P0(...) 0
#define BC_NB_P1(...) 1
#define BC_NB_P2(...) 2
#define BC_NB_P3(...) 3
#define BC_NB_P4(...) 4
static const int BC_size[] = {
#		define APPLY_BC(__x, __p, ...) BC_NB_##__p,
#		include "bc.def"
  0
};
#undef BC_NB_P0
#undef BC_NB_P1
#undef BC_NB_P2
#undef BC_NB_P3
#undef BC_NB_P4

typedef int *code_segment;

struct cpool_int { int size; int names; int *values; };
struct cpool_lgl { int size; int names; int *values; };
struct cpool_cplx { int size; int names; Rcomplex *values; };
struct cpool_real { int size; int names; double *values; };
//struct cpool_string { int size; int names; int *values; }; A string is nothing more than a vector
struct cpool_char { int size; char *value; };
struct cpool_vector { int size; int names; int* values; }; 

typedef struct { int type;
	union  {
		struct cpool_lgl	pe_lgl;
		struct cpool_int	pe_int;
		struct cpool_real	pe_real;
		struct cpool_cplx	pe_cplx;
		struct cpool_char	pe_char; // Symbol/String
		//struct cpool_string	pe_string;
		struct cpool_vector	pe_vector;
	} data;
} cpool_entry;

typedef struct {
  char magic[4];
  int pp; // CtPool Size
  int cs; // Code segment size
  int funinfos; // Function infos size
} bc_header;

typedef struct {
  int start;
  int end;
  int params;
} fun_info;

#ifdef __cplusplus
	extern "C" {
#endif

int read_bc_file(FILE *fd, bc_header *header, cpool_entry **cpool, fun_info **f_infos, code_segment *cs, void * (alloc) (size_t));
int read_funinfos(int *size, fun_info **infos, FILE *fd, void * (alloc) (size_t));

int write_bc_file(FILE *fd, bc_header *header, cpool_entry *cpool, fun_info *infos, code_segment cs);
int write_funinfos(int size, fun_info *infos, FILE *fd);
int write_const(cpool_entry *, FILE *);
int read_const(cpool_entry *, FILE *, void * (alloc) (size_t));
int write_segment(int size, code_segment, FILE *);

void dumpBCHeader(bc_header *header, void (print) (const char*, ...));
void dumpSegmentHeader(int size, code_segment segment, void (print) (const char*, ...));

void dumpBC(int size, code_segment seg, void (print)(const char*, ...));
void dumpMyBC(int *cs, int len, void (print)(const char*, ...));
void disassemble(int size, code_segment segment, cpool_entry *cpool, void (print) (const char*, ...));

void dumpPool(int cpool_len, cpool_entry *pe, void (print)(const char*, ...));
void dumpPE(cpool_entry *pe, void (print)(const char*, ...));
#ifdef __cplusplus
	}
#endif
#undef DECLARE

#endif
